package robot

import (
	"context"
	"sale-admin/config/mysql"
	"sale-admin/internal/app/grpc/client"
	"sale-admin/internal/app/grpc/protoc/devicec"
	"sale-admin/internal/app/grpc/protoc/system_admin"
	"sale-admin/internal/app/web/service"
	"sale-admin/internal/app/web/service/common"
	"sale-admin/internal/dal"
	"sale-admin/internal/dao"
	"sale-admin/internal/define"
	"sale-admin/internal/models"
	"sort"
	"strconv"
	"strings"
	"time"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/logx"
	"github.com/golang-module/carbon"
	"github.com/samber/lo"
	"gorm.io/gorm"
)

type FaceCount struct{}

type FaceCountList struct {
	Date         string  `json:"date"`
	RobotName    string  `json:"robot_name"`
	MerchantName string  `json:"merchant_name"`
	Province     string  `json:"province"`
	City         string  `json:"city"`
	District     string  `json:"district"`
	Location     string  `json:"location"`
	FaceCount    float64 `json:"face_count"`
	FaceCount0   float64 `json:"face_count0"`
	FaceCount1   float64 `json:"face_count1"`
	FaceCount2   float64 `json:"face_count2"`
	FaceCount3   float64 `json:"face_count3"`
}

// 上报曝光量
func (fc FaceCount) UpFaceData(ctx context.Context, db *gorm.DB, salesID, robotName string, StartTime, EndTime,
	FaceCount, FaceCount0, FaceCount1, FaceCount2, FaceCount3 int64, stareCount, stareCount0, stareCount1, stareCount2, stareCount3 int64,
	AgeGender []struct {
		Age    int64 `json:"Age"`
		Male   int64 `json:"Male"`
		Female int64 `json:"Female"`
	}) (err error) {
	// 需要获取机器的信息
	robotInfo, robotExist := RobotService{}.CheckRobotExist(ctx, db, salesID, robotName)
	if !robotExist {
		err = errorx.New("找不到机器人", -1)
		return
	}
	if StartTime <= 0 || EndTime <= 0 {
		logx.Error(ctx, "曝光量起止时间错误",
			logx.Any("robot_name", robotName),
			logx.Any("start_time", StartTime),
			logx.Any("end_time", EndTime),
		)
		err = errorx.New("开始时间或结束时间错误", -1)
		return
	}
	// 曝光量
	{
		merchantID, _ := strconv.ParseInt(robotInfo.MerchantID, 10, 64)
		dao.FaceCount{}.Create(ctx, dal.Q, merchantID, robotName, StartTime, EndTime,
			FaceCount, FaceCount0, FaceCount1, FaceCount2, FaceCount3, int64(robotInfo.Areas3))

		// 两天前的曝光量实时更新
		if StartTime < time.Now().Unix()-2*24*60*60 {
			date := carbon.CreateFromTimestamp(StartTime).ToDateString()
			service.RobotDailyReport{}.UpdateFaceCount(ctx, db, robotInfo.RobotName, date)
		}
	}
	// 凝视数据
	{
		// 凝视
		dao.StareCount{}.Save(ctx, dal.Q, robotInfo.MerchantID, robotName, StartTime, EndTime,
			stareCount, stareCount0, stareCount1, stareCount2, stareCount3, int64(robotInfo.Areas3))

		// 凝视类型 0前1左2右3总【一般为0，1，2】
		var stareType int64
		if stareCount0 > 0 {
			stareType = 0
		} else if stareCount1 > 0 {
			stareType = 1
		} else if stareCount2 > 0 {
			stareType = 2
		} else if stareCount3 > 0 {
			stareType = 3
		} else if stareCount > 0 {
			stareType = 4
		}
		// 凝视年龄性别
		dao.StareAgeGender{}.Save(ctx, dal.Q, robotInfo.MerchantID, robotName, StartTime, EndTime,
			stareType, int64(robotInfo.Areas3), AgeGender)

		// 两天前的凝视数据实时更新
		if StartTime < time.Now().Unix()-2*24*60*60 {
			date := carbon.CreateFromTimestamp(StartTime).ToDateString()
			service.RobotDailyReport{}.UpdateStareCount(ctx, db, robotInfo.RobotName, date)
		}
	}

	return
}

func (fc FaceCount) List(ctx context.Context, merchantID string, shopList []string, robotID string, startTime, endTime int64,
	provinceID, cityID, districtID, locationID string, page, limit int) (
	res []FaceCountList, count int64, summary dao.FaceCountTotal, err error,
) {
	// 默认今天
	if startTime == 0 && endTime == 0 {
		startTime = carbon.Now().StartOfDay().Timestamp()
		endTime = carbon.Now().EndOfDay().Timestamp()
	}
	start := carbon.CreateFromTimestamp(startTime).ToDateTimeString()
	end := carbon.CreateFromTimestamp(endTime).ToDateTimeString()

	var filterRobotID []string
	if robotID != "" {
		filterRobotID = strings.Split(robotID, ",")
	}
	var filterLocation []string
	if locationID != "" {
		filterLocation = strings.Split(locationID, ",")
	}

	SystemAdminClient, clientErr := client.GetSystemAdminClient()
	if clientErr != nil {
		return
	}
	// 商户筛选
	var filterMerchants = []string{} // 归属商户
	if merchantID != "1" {
		// 获取直系商户
		req := &system_admin.FamilyMerchantsReq{
			MerchantId: merchantID,
		}
		rsp, err1 := SystemAdminClient.GetFamilyMerchants(ctx, req)
		if err1 != nil {
			return
		}
		if len(shopList) > 0 {
			filterMerchants = lo.Intersect(rsp.MerchantIds, shopList)
		} else {
			filterMerchants = rsp.MerchantIds
		}
	} else {
		if len(shopList) > 0 {
			filterMerchants = shopList
		}
	}
	DeviceAdminClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		return
	}
	// 归属机器
	var validRobots = []string{}
	// 机器筛选
	if provinceID != "" || cityID != "" || districtID != "" || locationID != "" {
		req := &devicec.DeviceListReq{
			ProvinceId: provinceID, // 省
			CityId:     cityID,     // 市
			DistrictId: districtID, // 区
		}
		rsp, err2 := DeviceAdminClient.DeviceList(ctx, req)
		if err2 != nil {
			return
		}
		for _, v := range rsp.List {
			if len(filterLocation) > 0 && !lo.Contains(filterLocation, v.LocationId) {
				continue
			}
			if len(filterMerchants) > 0 && !lo.Contains(filterMerchants, v.MerchantId) {
				continue
			}
			if len(filterRobotID) > 0 && !lo.Contains(filterRobotID, v.RobotId) {
				continue
			}
			validRobots = append(validRobots, v.RobotId)
		}
		if len(validRobots) == 0 {
			return
		}
	} else {
		robotList, robotCount, _ := dao.Robot{}.RobotList(ctx, mysql.NewDB(), strings.Join(filterMerchants, ","),
			"", robotID, "", "", "", "", "")
		if robotCount == 0 {
			return
		}
		for _, v := range robotList {
			validRobots = append(validRobots, v.RobotName)
		}
	}

	// 总数
	summary = dao.FaceCount{}.GetFaceCountTotal(ctx, dal.Q, filterMerchants, strings.Join(validRobots, ","),
		start, end)
	// 列表
	list, count := dao.FaceCount{}.GetFaceCountList(ctx, dal.Q, filterMerchants, strings.Join(validRobots, ","),
		start, end, define.DAY, 2, page, limit)

	res = []FaceCountList{}
	if count == 0 {
		return
	}
	var robotNames []string
	for _, v := range list {
		if !lo.Contains(robotNames, v.RobotName) {
			robotNames = append(robotNames, v.RobotName)
		}
	}

	// 机器信息
	robotList, _, _ := dao.Robot{}.RobotList(ctx, mysql.NewDB(), "", "", strings.Join(robotNames, ","), "", "", "", "", "")
	var robotMap = make(map[string]*models.MaRobot)
	var merchantIds []string
	for _, v := range robotList {
		robotMap[v.RobotName] = v
		if !lo.Contains(merchantIds, v.MerchantID) {
			merchantIds = append(merchantIds, v.MerchantID)
		}
	}
	merchantReq := &system_admin.MerchantNameReq{
		MerchantIds: merchantIds,
	}
	merchantNameMapRes, err1 := SystemAdminClient.MerchantName(ctx, merchantReq)
	if err1 != nil {
		return
	}
	// 位置
	deviceReq := &devicec.LocationListReq{}
	deviceRes, err := DeviceAdminClient.LocationList(context.Background(), deviceReq)
	var LocationMap = make(map[string]string)
	areaIDList := []string{}
	if deviceRes != nil && deviceRes.Code == 0 && err == nil {
		for _, v := range deviceRes.List {
			LocationMap[v.Id] = v.Name
			areaIDList = append(areaIDList, v.ProvinceId)
			areaIDList = append(areaIDList, v.CityId)
			areaIDList = append(areaIDList, v.DistrictId)
		}
	}
	// GRPC获取省市区名称
	var AreaNameMap = make(map[string]string)
	var req system_admin.AreaLisRequest
	req.AreaIDs = areaIDList
	areaRes, err1 := SystemAdminClient.AreaList(context.Background(), &req)
	if err1 != nil {
		logx.Error(context.Background(), "areas error", logx.Any("res", areaRes), logx.Any("err", err1.Error()))
		return
	}
	for _, v := range areaRes.Areas {
		AreaNameMap[v.ID] = v.Name
	}
	for _, v := range list {
		item := FaceCountList{}
		item.RobotName = v.RobotName
		item.Date = v.Date
		item.FaceCount = v.FaceCount
		item.FaceCount0 = v.FaceCount0
		item.FaceCount1 = v.FaceCount1
		item.FaceCount2 = v.FaceCount2
		item.FaceCount3 = v.FaceCount3
		if robotInfo, ok := robotMap[v.RobotName]; ok {
			// 商户名称
			if merchantNameMapRes != nil && merchantNameMapRes.MerchantNameMap != nil {
				if merchantName, ok := merchantNameMapRes.MerchantNameMap[robotInfo.MerchantID]; ok {
					item.MerchantName = merchantName
				}
			}
			// 省市区 位置
			locationID := strconv.Itoa(robotInfo.Areas3)
			provinceID := strconv.Itoa(robotInfo.Areas1)
			cityID := strconv.Itoa(robotInfo.Areas2)
			districtID := strconv.Itoa(robotInfo.Areas5)
			if locationName, ok := LocationMap[locationID]; ok {
				item.Location = locationName
			}
			if province, ok := AreaNameMap[provinceID]; ok {
				item.Province = province
			}
			if city, ok := AreaNameMap[cityID]; ok {
				item.City = city
			}
			if district, ok := AreaNameMap[districtID]; ok {
				item.District = district
			}
		}
		res = append(res, item)
	}
	return
}

// 曝光量总入口
func (fc FaceCount) GetFaceCount(ctx context.Context, db *gorm.DB, merchantID string,
	areas3, startTime, endTime, salesID string, shopIDList []string, timeType int, getTotal bool) (
	data []dao.FaceCountList, totalCount float64, err error,
) {
	merchantIDList, err1 := common.Order{}.GetMerchantChildren(ctx, merchantID, shopIDList)
	if err1 != nil {
		err = err1
		return
	}
	if timeType >= define.HOUR && timeType <= define.YEAR {
		common.HandlerTime(&startTime, &endTime, timeType)

		robotList, _, _ := dao.Robot{}.RobotList(ctx, db, "", "", "", salesID, "", "", "", "")
		var RobotNameList = []string{}
		for _, v := range robotList {
			if areas3 != "" {
				locationID := strconv.Itoa(v.Areas3)
				if lo.Contains(strings.Split(areas3, ","), locationID) {
					RobotNameList = append(RobotNameList, v.RobotName)
				}
			} else {
				RobotNameList = append(RobotNameList, v.RobotName)
			}
		}
		robotNames := strings.Join(RobotNameList, ",")
		FaceCountList, _ := dao.FaceCount{}.GetFaceCountList(ctx, dal.Q, merchantIDList, robotNames, startTime, endTime, timeType, 1, 0, 0)
		if getTotal {
			faceCountTotal := dao.FaceCount{}.GetFaceCountTotal(ctx, dal.Q, merchantIDList, robotNames, startTime, endTime)
			totalCount = faceCountTotal.FaceCount
		}
		//填充时间
		FullTimeList := common.GetPeriodsByType(startTime, endTime, timeType)
		var FullTimeResult = []dao.FaceCountList{}
		for _, v := range FullTimeList {
			var dateRes = dao.FaceCountList{}
			for _, res := range FaceCountList {
				if v == res.Date {
					dateRes = res
					break
				}
			}
			dateRes.Date = v
			FullTimeResult = append(FullTimeResult, dateRes)
		}

		if timeType == define.WEEK {
			for k, v := range FullTimeResult {
				FullTimeResult[k].YearWeek = common.GetWeekOfYear(v.Date)
			}
			var WeekResultMap = make(map[string]dao.FaceCountList)
			for _, v := range FullTimeResult {
				var item dao.FaceCountList
				if _, ok := WeekResultMap[v.YearWeek]; ok {
					item = WeekResultMap[v.YearWeek]
				}
				item.FaceCount += v.FaceCount
				item.Date = strings.Split(v.YearWeek, "_")[0] + "年 第" + strings.Split(v.YearWeek, "_")[1] + "周"
				item.YearWeek = v.YearWeek
				WeekResultMap[v.YearWeek] = item
			}
			data = lo.MapToSlice(WeekResultMap, func(k string, v dao.FaceCountList) dao.FaceCountList {
				return v
			})
			sort.Slice(data, func(i, j int) bool {
				return data[i].YearWeek < data[j].YearWeek
			})
			return data, totalCount, nil
		} else {
			return FullTimeResult, totalCount, nil
		}
	}
	return
}

// 曝光统计
// 开始和结束时间，后面默认页面不触发查询
func (fc FaceCount) DatePerson(ctx context.Context, db *gorm.DB, merchantID string, shopIDList []string,
	areas3 string, startTime, endTime, salesID string, page, limit int) (data interface{}, count int64, err error) {
	if startTime != "" && endTime != "" {
		startTime = carbon.Parse(startTime).StartOfDay().ToDateTimeString()
		endTime = carbon.Parse(endTime).EndOfDay().ToDateTimeString()
	}
	// 处理分页
	if page == 1 && !(startTime != "" && endTime != "") {
		startTime = carbon.Now().SubDays(limit).ToDateString()
		endTime = carbon.Now().ToDateString()
	} else if !(startTime != "" && endTime != "") {
		startTime = carbon.Now().SubDays(limit * (page - 1)).ToDateString()
		endTime = carbon.Now().SubDays(limit * page).ToDateString()
		page = 1
	}

	// 搜索时间范围大于limit显示天数，则分页处理
	var LastCountData int64
	if startTime != "" && endTime != "" {
		LastCountData = carbon.Parse(endTime).DiffAbsInSeconds(carbon.Parse(startTime))
		if int(LastCountData) > limit*86400 {
			count = LastCountData / 86400
			if (carbon.Parse(endTime).Timestamp() - int64(limit*page*86400)) >= carbon.Parse(startTime).Timestamp() {
				startTime = carbon.Parse(endTime).SubSeconds(limit*page*86400 - 1).ToDateTimeString()
			}
			endTime = carbon.Parse(endTime).SubSeconds(limit * (page - 1) * 86400).ToDateTimeString()
		} else {
			count = int64(limit)
		}
	}
	var Res = struct {
		FaceCount24       []dao.FaceCountList   `json:"face_count"`
		FaceCount24Robots [][]dao.FaceCountList `json:"face_count_robots"`
	}{}

	// 商户
	merchantIDList, _ := common.Order{}.GetMerchantChildren(ctx, merchantID, shopIDList)
	// 【2 时间+机器】分组的曝光量
	robotList, _, _ := dao.Robot{}.RobotList(ctx, db, "", "", "", salesID, "", "", "", "")
	var RobotNameList = []string{}
	for _, v := range robotList {
		if areas3 != "" {
			locationID := strconv.Itoa(v.Areas3)
			if lo.Contains(strings.Split(areas3, ","), locationID) {
				RobotNameList = append(RobotNameList, v.RobotName)
			}
		} else {
			RobotNameList = append(RobotNameList, v.RobotName)
		}
	}
	robotNames := strings.Join(RobotNameList, ",")
	res, _ := dao.FaceCount{}.GetFaceCountList(ctx, dal.Q, merchantIDList, robotNames, startTime, endTime, define.DAY, 2, 0, 0)

	FaceCount24RobotsMap := make(map[string][]dao.FaceCountList)
	for _, v := range res {
		FaceCount24RobotsMap[v.Date] = append(FaceCount24RobotsMap[v.Date], v)
	}

	// 定义二维切片
	var FaceCount24Robots = [][]dao.FaceCountList{}
	for _, v := range FaceCount24RobotsMap {
		FaceCount24Robots = append(FaceCount24Robots, v)
	}

	Res.FaceCount24Robots = FaceCount24Robots

	// 【1 时间】分组的曝光量
	FaceCount, _, _ := FaceCount{}.GetFaceCount(ctx, db, merchantID, areas3, startTime, endTime, salesID, shopIDList, define.DAY, false)
	Res.FaceCount24 = FaceCount
	return Res, count, err
}
